/**
 * @fileOverview The "wysiwygarea" plugin. It registers the "wysiwyg" editing
 *      mode, which handles the main editing area space.
 */
(function() {
   VED.plugins.add( 'wysiwygarea', {
      init: function( editor ) {
         if ( editor.config.fullPage ) {
            editor.addFeature( {
               allowedContent: 'html head title; style [media,type]; body (*)[id]; meta link [*]',
               requiredContent: 'body'
            } );
         }

         editor.addMode( 'wysiwyg', function( callback ) {
            var src = 'document.open();' +
               // In IE, the document domain must be set any time we call document.open().
               ( VED.env.ie ? '(' + VED.tools.fixDomain + ')();' : '' ) +
               'document.close();';

            // With IE, the custom domain has to be taken care at first,
            // for other browers, the 'src' attribute should be left empty to
            // trigger iframe's 'load' event.
            src = VED.env.air ? 'javascript:void(0)' : VED.env.ie ? 'javascript:void(function(){' + encodeURIComponent( src ) + '}())'
               :
               '';

            var iframe = VED.dom.element.createFromHtml( '<iframe src="' + src + '" frameBorder="0"></iframe>' );
            iframe.setStyles( { width: '100%', height: '100%' } );
            iframe.addClass( 'ved_wysiwyg_frame ved_reset' );

            var contentSpace = editor.ui.space( 'contents' );
            contentSpace.append( iframe );


            // Asynchronous iframe loading is only required in IE>8 and Gecko (other reasons probably).
            // Do not use it on WebKit as it'll break the browser-back navigation.
            var useOnloadEvent = VED.env.ie || VED.env.gecko;
            if ( useOnloadEvent )
               iframe.on( 'load', onLoad );

            var frameLabel = [ editor.lang.editor, editor.name ].join( ',' ),
               frameDesc = editor.lang.common.editorHelp;

            if ( VED.env.ie )
               frameLabel += ', ' + frameDesc;

            var labelId = VED.tools.getNextId(),
               desc = VED.dom.element.createFromHtml( '<span id="' + labelId + '" class="ved_voice_label">' + frameDesc + '</span>' );

            contentSpace.append( desc, 1 );

            // Remove the ARIA description.
            editor.on( 'beforeModeUnload', function( evt ) {
               evt.removeListener();
               desc.remove();
            });

            iframe.setAttributes({
               'aria-describedby' : labelId,
               title: frameLabel,
               tabIndex: editor.tabIndex,
               allowTransparency: 'true'
            });

            // Execute onLoad manually for all non IE||Gecko browsers.
            !useOnloadEvent && onLoad();

            if ( VED.env.webkit ) {
               // Webkit: iframe size doesn't auto fit well. (#7360)
               var onResize = function() {
                  // Hide the iframe to get real size of the holder. (#8941)
                  contentSpace.setStyle( 'width', '100%' );

                  iframe.hide();
                  iframe.setSize( 'width', contentSpace.getSize( 'width' ) );
                  contentSpace.removeStyle( 'width' );
                  iframe.show();
               };

               iframe.setCustomData( 'onResize', onResize );

               VED.document.getWindow().on( 'resize', onResize );
            }

            editor.fire( 'ariaWidget', iframe );

            function onLoad( evt ) {
               evt && evt.removeListener();
               editor.editable( new framedWysiwyg( editor, iframe.$.contentWindow.document.body ) );
               editor.setData( editor.getData( 1 ), callback );
            }
         });
      }
   });

   function onDomReady( win ) {
      var editor = this.editor,
         doc = win.document,
         body = doc.body;

      // Remove helper scripts from the DOM.
      var script = doc.getElementById( 'ved_actscrpt' );
      script && script.parentNode.removeChild( script );
      script = doc.getElementById( 'ved_shimscrpt' );
      script && script.parentNode.removeChild( script );

      if ( VED.env.gecko ) {
         // Force Gecko to change contentEditable from false to true on domReady
         // (because it's previously set to true on iframe's body creation).
         // Otherwise del/backspace and some other editable features will be broken in Fx <4
         // See: #107 and https://bugzilla.mozilla.org/show_bug.cgi?id=440916
         body.contentEditable = false;

         // Remove any leading <br> which is between the <body> and the comment.
         // This one fixes Firefox 3.6 bug: the browser inserts a leading <br>
         // on document.write if the body has contenteditable="true".
         if ( VED.env.version < 20000 ) {
            body.innerHTML = body.innerHTML.replace( /^.*<!-- ved-content-start -->/, '' );

            // The above hack messes up the selection in FF36.
            // To clean this up, manually select collapsed range that
            // starts within the body.
            setTimeout( function() {
               var range = new VED.dom.range( new VED.dom.document( doc ) );
               range.setStart( new VED.dom.node( body ), 0 );
               editor.getSelection().selectRanges( [ range ] );
            }, 0 );
         }
      }

      body.contentEditable = true;

      if ( VED.env.ie ) {
         // Don't display the focus border.
         body.hideFocus = true;

         // Disable and re-enable the body to avoid IE from
         // taking the editing focus at startup. (#141 / #523)
         body.disabled = true;
         body.removeAttribute( 'disabled' );
      }

      delete this._.isLoadingData;

      // Play the magic to alter element reference to the reloaded one.
      this.$ = body;

      doc = new VED.dom.document( doc );

      this.setup();

      if ( VED.env.ie ) {
         doc.getDocumentElement().addClass( doc.$.compatMode );

         // Prevent IE from leaving new paragraph after deleting all contents in body. (#6966)
         editor.config.enterMode != VED.ENTER_P && doc.on( 'selectionchange', function() {
            var body = doc.getBody(),
               sel = editor.getSelection(),
               range = sel && sel.getRanges()[ 0 ];

            if ( range && body.getHtml().match( /^<p>&nbsp;<\/p>$/i ) && range.startContainer.equals( body ) ) {
               // Avoid the ambiguity from a real user cursor position.
               setTimeout( function() {
                  range = editor.getSelection().getRanges()[ 0 ];
                  if ( !range.startContainer.equals( 'body' ) ) {
                     body.getFirst().remove( 1 );
                     range.moveToElementEditEnd( body );
                     range.select();
                  }
               }, 0 );
            }
         });
      }

      // Gecko needs a key event to 'wake up' editing when the document is
      // empty. (#3864, #5781)
      VED.env.gecko && VED.tools.setTimeout( activateEditing, 0, this, editor );

      // ## START : disableNativeTableHandles and disableObjectResizing settings.

      // Enable dragging of position:absolute elements in IE.
      try {
         editor.document.$.execCommand( '2D-position', false, true );
      } catch ( e ) {}

      // IE, Opera and Safari may not support it and throw errors.
      try {
         editor.document.$.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles );
      } catch ( e ) {}

      if ( editor.config.disableObjectResizing ) {
         try {
            this.getDocument().$.execCommand( 'enableObjectResizing', false, false );
         } catch ( e ) {
            // For browsers in which the above method failed, we can cancel the resizing on the fly (#4208)
            this.attachListener( this, VED.env.ie ? 'resizestart' : 'resize', function( evt ) {
               evt.data.preventDefault();
            });
         }
      }

      if ( VED.env.gecko || VED.env.ie && editor.document.$.compatMode == 'CSS1Compat' ) {
         this.attachListener( this, 'keydown', function( evt ) {
            var keyCode = evt.data.getKeystroke();

            // PageUp OR PageDown
            if ( keyCode == 33 || keyCode == 34 ) {
               // PageUp/PageDown scrolling is broken in document
               // with standard doctype, manually fix it. (#4736)
               if ( VED.env.ie ) {
                  setTimeout( function() {
                     editor.getSelection().scrollIntoView();
                  }, 0 );
               }
               // Page up/down cause editor selection to leak
               // outside of editable thus we try to intercept
               // the behavior, while it affects only happen
               // when editor contents are not overflowed. (#7955)
               else if ( editor.window.$.innerHeight > this.$.offsetHeight ) {
                  var range = editor.createRange();
                  range[ keyCode == 33 ? 'moveToElementEditStart' : 'moveToElementEditEnd' ]( this );
                  range.select();
                  evt.data.preventDefault();
               }
            }
         });
      }

      if ( VED.env.ie ) {
         // [IE] Iframe will still keep the selection when blurred, if
         // focus is moved onto a non-editing host, e.g. link or button, but
         // it becomes a problem for the object type selection, since the resizer
         // handler attached on it will mark other part of the UI, especially
         // for the dialog. (#8157)
         // [IE<8 & Opera] Even worse For old IEs, the cursor will not vanish even if
         // the selection has been moved to another text input in some cases. (#4716)
         //
         // Now the range restore is disabled, so we simply force IE to clean
         // up the selection before blur.
         this.attachListener( doc, 'blur', function() {
            // Error proof when the editor is not visible. (#6375)
            try {
               doc.$.selection.empty();
            } catch ( er ) {}
         });
      }

      // ## END


      var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );
      title.data( 'ved-title', editor.document.$.title );

      // [IE] JAWS will not recognize the aria label we used on the iframe
      // unless the frame window title string is used as the voice label,
      // backup the original one and restore it on output.
      if ( VED.env.ie )
         editor.document.$.title = this._.docTitle;

      VED.tools.setTimeout( function() {
         editor.fire( 'contentDom' );

         if ( this._.isPendingFocus ) {
            editor.focus();
            this._.isPendingFocus = false;
         }

         setTimeout( function() {
            editor.fire( 'dataReady' );
         }, 0 );

         // IE BUG: IE might have rendered the iframe with invisible contents.
         // (#3623). Push some inconsequential CSS style changes to force IE to
         // refresh it.
         //
         // Also, for some unknown reasons, short timeouts (e.g. 100ms) do not
         // fix the problem. :(
         if ( VED.env.ie ) {
            setTimeout( function() {
               if ( editor.document ) {
                  var $body = editor.document.$.body;
                  $body.runtimeStyle.marginBottom = '0px';
                  $body.runtimeStyle.marginBottom = '';
               }
            }, 1000 );
         }
      }, 0, this );
   }

   var framedWysiwyg = VED.editable.extend({
      initialize: function( editor ) {
         this.parent.apply( this, arguments );

         this._.frameLoadedHandler = VED.tools.addFunction( function( win ) {
            // Avoid opening design mode in a frame window thread,
            // which will cause host page scrolling.(#4397)
            VED.tools.setTimeout( onDomReady, 0, this, win );
         }, this );

         this._.docTitle = this.getWindow().getFrame().getAttribute( 'title' );
      },

      setData: function( data, isSnapshot ) {
         var editor = this.editor;

         if ( isSnapshot )
            this.setHtml( data );
         else {
            this._.isLoadingData = true;
            editor._.dataStore = { id:1 };

            var config = editor.config,
               fullPage = config.fullPage,
               docType = config.docType;

            // Build the additional stuff to be included into <head>.
            var headExtra = VED.tools.buildStyleHtml( iframeCssFixes() )
                               .replace( /<style>/, '<style data-ved-temp="1">' );

            if ( !fullPage )
               headExtra += VED.tools.buildStyleHtml( editor.config.contentsCss );

            var baseTag = config.baseHref ? '<base href="' + config.baseHref + '" data-ved-temp="1" />' : '';

            if ( fullPage ) {
               // Search and sweep out the doctype declaration.
               data = data.replace( /<!DOCTYPE[^>]*>/i, function( match ) {
                  editor.docType = docType = match;
                  return '';
               }).replace( /<\?xml\s[^\?]*\?>/i, function( match ) {
                  editor.xmlDeclaration = match;
                  return '';
               });
            }

            // Get the HTML version of the data.
            if ( editor.dataProcessor )
               data = editor.dataProcessor.toHtml( data );

            if ( fullPage ) {
               // Check if the <body> tag is available.
               if ( !( /<body[\s|>]/ ).test( data ) )
                  data = '<body>' + data;

               // Check if the <html> tag is available.
               if ( !( /<html[\s|>]/ ).test( data ) )
                  data = '<html>' + data + '</html>';

               // Check if the <head> tag is available.
               if ( !( /<head[\s|>]/ ).test( data ) )
                  data = data.replace( /<html[^>]*>/, '$&<head><title></title></head>' );
               else if ( !( /<title[\s|>]/ ).test( data ) )
                  data = data.replace( /<head[^>]*>/, '$&<title></title>' );

               // The base must be the first tag in the HEAD, e.g. to get relative
               // links on styles.
               baseTag && ( data = data.replace( /<head>/, '$&' + baseTag ) );

               // Inject the extra stuff into <head>.
               // Attention: do not change it before testing it well. (V2)
               // This is tricky... if the head ends with <meta ... content type>,
               // Firefox will break. But, it works if we place our extra stuff as
               // the last elements in the HEAD.
               data = data.replace( /<\/head\s*>/, headExtra + '$&' );

               // Add the DOCTYPE back to it.
               data = docType + data;
            } else {
               data = config.docType +
                  '<html dir="' + config.contentsLangDirection + '"' +
                     ' lang="' + ( config.contentsLanguage || editor.langCode ) + '">' +
                  '<head>' +
                     '<title>' + this._.docTitle + '</title>' +
                     baseTag +
                     headExtra +
                  '</head>' +
                  '<body' + ( config.bodyId ? ' id="' + config.bodyId + '"' : '' ) +
                     ( config.bodyClass ? ' class="' + config.bodyClass + '"' : '' ) +
                  '>' +
                     data +
                  '</body>' +
                  '</html>';
            }

            if ( VED.env.gecko ) {
               // Hack to make Fx put cursor at the start of doc on fresh focus.
               data = data.replace( /<body/, '<body contenteditable="true" ' );

               // Another hack which is used by onDomReady to remove a leading
               // <br> which is inserted by Firefox 3.6 when document.write is called.
               // This additional <br> is present because of contenteditable="true"
               if ( VED.env.version < 20000 )
                  data = data.replace( /<body[^>]*>/, '$&<!-- ved-content-start -->'  );
            }

            // The script that launches the bootstrap logic on 'domReady', so the document
            // is fully editable even before the editing iframe is fully loaded (#4455).
            var bootstrapCode =
               '<script id="ved_actscrpt" type="text/javascript"' + ( VED.env.ie ? ' defer="defer" ' : '' ) + '>' +
                  'var wasLoaded=0;' +   // It must be always set to 0 as it remains as a window property.
                  'function onload(){' +
                     'if(!wasLoaded)' +   // FF3.6 calls onload twice when editor.setData. Stop that.
                        'window.parent.VED.tools.callFunction(' + this._.frameLoadedHandler + ',window);' +
                     'wasLoaded=1;' +
                  '}' +
                  ( VED.env.ie ? 'onload();' : 'document.addEventListener("DOMContentLoaded", onload, false );' ) +
               '</script>';

            // For IE<9 add support for HTML5's elements.
            // Note: this code must not be deferred.
            if ( VED.env.ie && VED.env.version < 9 ) {
               bootstrapCode +=
                  '<script id="ved_shimscrpt">' +
                     '(function(){' +
                        'var e="abbr,article,aside,audio,bdi,canvas,data,datalist,details,figcaption,figure,footer,header,hgroup,mark,meter,nav,output,progress,section,summary,time,video".split(","),i=e.length;' +
                        'while(i--){document.createElement(e[i])}' +
                     '})()' +
                  '</script>';
            }

            data = data.replace( /(?=\s*<\/(:?head)>)/, bootstrapCode );

            // Current DOM will be deconstructed by document.write, cleanup required.
            this.clearCustomData();
            this.clearListeners();

            editor.fire( 'contentDomUnload' );

            var doc = this.getDocument();

            // Work around Firefox bug - error prune when called from XUL (#320),
            // defer it thanks to the async nature of this method.
            try { doc.write( data ); } catch ( e ) {
               setTimeout( function () { doc.write( data ); }, 0 );
            }
         }
      },

      getData: function( isSnapshot ) {
         if ( isSnapshot )
            return this.getHtml();
         else {
            var editor = this.editor,
               config = editor.config,
               fullPage = config.fullPage,
               docType = fullPage && editor.docType,
               xmlDeclaration = fullPage && editor.xmlDeclaration,
               doc = this.getDocument();

            var data = fullPage ? doc.getDocumentElement().getOuterHtml() : doc.getBody().getHtml();

            // BR at the end of document is bogus node for Mozilla. (#5293).
            // Prevent BRs from disappearing from the end of the content
            // while enterMode is ENTER_BR (#10146).
            if ( VED.env.gecko && config.enterMode != VED.ENTER_BR )
               data = data.replace( /<br>(?=\s*(:?$|<\/body>))/, '' );

            if ( editor.dataProcessor )
               data = editor.dataProcessor.toDataFormat( data );

            if ( xmlDeclaration )
               data = xmlDeclaration + '\n' + data;
            if ( docType )
               data = docType + '\n' + data;

            return data;
         }
      },

      focus: function() {
         if ( this._.isLoadingData )
            this._.isPendingFocus = true;
         else
            this.parent.call( this );
      },

      detach: function() {
         var editor = this.editor,
            doc = editor.document,
            iframe = editor.window.getFrame();

         this.parent.call( this );

         // Memory leak proof.
         this.clearCustomData();
         doc.getDocumentElement().clearCustomData();
         iframe.clearCustomData();
         VED.tools.removeFunction( this._.frameLoadedHandler );

         var onResize = iframe.removeCustomData( 'onResize' );
         onResize && onResize.removeListener();


         editor.fire( 'contentDomUnload' );

         // IE BUG: When destroying editor DOM with the selection remains inside
         // editing area would break IE7/8's selection system, we have to put the editing
         // iframe offline first. (#3812 and #5441)
         iframe.remove();
      }
   });

   // DOM modification here should not bother dirty flag.(#4385)
   function restoreDirty( editor ) {
      if ( !editor.checkDirty() )
         setTimeout( function() {
         editor.resetDirty();
      }, 0 );
   }

   function activateEditing( editor ) {
      if ( editor.readOnly )
         return;

      var win = editor.window,
         doc = editor.document,
         body = doc.getBody(),
         bodyFirstChild = body.getFirst(),
         bodyChildsNum = body.getChildren().count();

      if ( !bodyChildsNum || bodyChildsNum == 1 && bodyFirstChild.type == VED.NODE_ELEMENT && bodyFirstChild.hasAttribute( '_moz_editor_bogus_node' ) ) {
         restoreDirty( editor );

         // Memorize scroll position to restore it later (#4472).
         var hostDocument = VED.document;
         var hostDocumentElement = hostDocument.getDocumentElement();
         var scrollTop = hostDocumentElement.$.scrollTop;
         var scrollLeft = hostDocumentElement.$.scrollLeft;

         // Simulating keyboard character input by dispatching a keydown of white-space text.
         var keyEventSimulate = doc.$.createEvent( "KeyEvents" );
         keyEventSimulate.initKeyEvent( 'keypress', true, true, win.$, false, false, false, false, 0, 32 );
         doc.$.dispatchEvent( keyEventSimulate );

         if ( scrollTop != hostDocumentElement.$.scrollTop || scrollLeft != hostDocumentElement.$.scrollLeft )
            hostDocument.getWindow().$.scrollTo( scrollLeft, scrollTop );

         // Restore the original document status by placing the cursor before a bogus br created (#5021).
         bodyChildsNum && body.getFirst().remove();
         doc.getBody().appendBogus();
         var nativeRange = editor.createRange();
         nativeRange.setStartAt( body, VED.POSITION_AFTER_START );
         nativeRange.select();
      }
   }

   function iframeCssFixes() {
      var css = [];

      // IE>=8 stricts mode doesn't have 'contentEditable' in effect
      // on element unless it has layout. (#5562)
      if ( VED.document.$.documentMode >= 8 ) {
         css.push( 'html.CSS1Compat [contenteditable=false]{min-height:0 !important}' );

         var selectors = [];

         for ( var tag in VED.dtd.$removeEmpty )
            selectors.push( 'html.CSS1Compat ' + tag + '[contenteditable=false]' );

         css.push( selectors.join( ',' ) + '{display:inline-block}' );
      }
      // Set the HTML style to 100% to have the text cursor in affect (#6341)
      else if ( VED.env.gecko ) {
         css.push( 'html{height:100% !important}' );
         css.push( 'img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}' );
      }

      // #6341: The text cursor must be set on the editor area.
      // #6632: Avoid having "text" shape of cursor in IE7 scrollbars.
      css.push( 'html{cursor:text;*cursor:auto}' );

      // Use correct cursor for these elements
      css.push( 'img,input,textarea{cursor:default}' );

      return css.join('\n');
   }
})();


VED.config.disableObjectResizing = false;
VED.config.disableNativeTableHandles = true;
VED.config.disableNativeSpellChecker = false;
VED.config.contentsCss = VED.basePath + 'contents.css';






